package com.ponhu.ea2.stockcenter.provider.service.rpc.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ponhu.ea2.stockcenter.dto.OrderInfoDTO;
import com.ponhu.ea2.stockcenter.dto.OrderInventoryInfo;
import com.ponhu.ea2.stockcenter.enums.DefinedSystem;
import com.ponhu.ea2.stockcenter.provider.constants.CommonConstant;
import com.ponhu.ea2.stockcenter.provider.decorators.Idempotence;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryDocOccupy;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryReal;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryUnreal;
import com.ponhu.ea2.stockcenter.provider.service.biz.stocksales.SalesLevelStockResponseService;
import com.ponhu.ea2.stockcenter.provider.service.entity.StockInventoryRealService;
import com.ponhu.ea2.stockcenter.provider.service.entity.StockInventoryUnrealService;
import com.ponhu.ea2.stockcenter.provider.support.enums.StockChangeInnerEventEnum;
import com.ponhu.ea2.stockcenter.provider.support.service.RabbitMQService;
import com.ponhu.ea2.stockcenter.provider.support.service.RedisSupportService;
import com.ponhu.ea2.stockcenter.provider.support.validation.ValidateUtils;
import com.ponhu.ea2.stockcenter.service.bms.StockForOMSService;
import com.ponhu.ea2.stockcenter.vo.OrderOccupyInfoVO;
import com.ponhu.ea2.stockcenter.vo.ReturnResponseBean;
import com.ponhu.ea2.stockcenter.vo.SalesLevelInventoryStockInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@DubboService(version = "1.0.0", interfaceClass = StockForOMSService.class, timeout = 60000)
public class StockForOMSServiceImpl implements StockForOMSService {

    @Autowired
    private StockInventoryRealService stockInventoryRealService;

    @Autowired
    private StockInventoryUnrealService stockInventoryUnrealService;

    @Autowired
    private SalesLevelStockResponseService salesLevelStockResponseService;

    @Autowired
    private RedisSupportService redisSupportService;

    @Autowired
    protected RabbitMQService rabbitMQService;

    @Idempotence
    @Override
    public ReturnResponseBean<OrderOccupyInfoVO> salesOrderOccupyStock(String stockRequestToken, OrderInfoDTO orderInfoDTO) {
        ValidateUtils.validateFirst(orderInfoDTO);

        ReturnResponseBean<OrderOccupyInfoVO> returnResponseBean = ((StockForOMSServiceImpl) AopContext.currentProxy())
                .salesOrderOccupyStock_Transactional(stockRequestToken, orderInfoDTO);

        // 销售库存变动发送MQ
        CompletableFuture.runAsync(() -> {
            List<String> inventoryCodeList = orderInfoDTO.getOrderInventoryInfoList()
                    .stream().map(OrderInventoryInfo::getInventoryCode).collect(Collectors.toList());
            rabbitMQService.saleStockChangeSendMsg(inventoryCodeList);
        });

        return returnResponseBean;
    }

    @Transactional(rollbackFor = Exception.class)
    public ReturnResponseBean<OrderOccupyInfoVO> salesOrderOccupyStock_Transactional(String stockRequestToken, OrderInfoDTO orderInfoDTO) {

        return salesLevelStockResponseService.orderOccupyStockHandler(stockRequestToken, orderInfoDTO, DefinedSystem.OMS, StockChangeInnerEventEnum.SALES_ORDER);
    }

    @Idempotence
    @Override
    public ReturnResponseBean cancelSalesOrderOccupyStock(String stockRequestToken, String orderNo) {

        ReturnResponseBean returnResponseBean = ((StockForOMSServiceImpl) AopContext.currentProxy())
                .cancelSalesOrderOccupyStock_Transactional(stockRequestToken, orderNo);

        // 销售库存变动发送MQ
        CompletableFuture.runAsync(() -> rabbitMQService.saleStockChangeSendMsg(orderNo));

        return returnResponseBean;
    }

    @Transactional(rollbackFor = Exception.class)
    public ReturnResponseBean cancelSalesOrderOccupyStock_Transactional(String stockRequestToken, String orderNo) {

        return salesLevelStockResponseService.cancelOrderOccupyStockHandler(stockRequestToken, orderNo, DefinedSystem.OMS, StockChangeInnerEventEnum.CANCEL_SALES_ORDER);
    }

    @Override
    public ReturnResponseBean<List<SalesLevelInventoryStockInfoVO>> getRealSalesStockInfo(List<String> inventoryCodeList) {
        //校验参数
        if (CollectionUtils.isEmpty(inventoryCodeList)) {
            return ReturnResponseBean.ok(new ArrayList<>());
        }

        return redisSupportService.wrapWithReadLock(inventoryCodeList, () -> {
            //获取实物类库存数
            List<StockInventoryReal> realStockList = stockInventoryRealService.getRealInventoryStockList(inventoryCodeList);
            log.info("销售层：获取实物库存数成功");
            //获取虚拟类库存数
            List<StockInventoryUnreal> unRealStockList = stockInventoryUnrealService.getUnRealInventoryStockList(inventoryCodeList);
            log.info("销售层：获取虚拟库存数成功");

            //计算实际可售库存数(实物类可售 - 实物类占用 + 虚拟类可售)
            List<SalesLevelInventoryStockInfoVO> realSalesStock = calcSalesLevelRealSalesStock(inventoryCodeList, realStockList, unRealStockList);
            log.info("销售层：汇总计算实际可售库存数成功");
            return new ReturnResponseBean<>(realSalesStock);
        });
    }

    private List<SalesLevelInventoryStockInfoVO> calcSalesLevelRealSalesStock(List<String> inventoryCodeList, List<StockInventoryReal> realStockList, List<StockInventoryUnreal> unRealStockList) {
        return inventoryCodeList.stream().map(i -> {
            StockInventoryReal realStock = realStockList.stream().filter(r -> i.equals(r.getInventoryCode())).collect(Collectors.toList()).stream().findFirst().orElse(null);
            StockInventoryUnreal unRealStock = unRealStockList.stream().filter(r -> i.equals(r.getInventoryCode())).collect(Collectors.toList()).stream().findFirst().orElse(null);

            SalesLevelInventoryStockInfoVO stockInfoVO = new SalesLevelInventoryStockInfoVO();
            stockInfoVO.setInventoryCode(i);

            int realSalesNum = 0;
            if (realStock != null) {
                realSalesNum = realStock.getSaleStockNum() - realStock.getUsedStockNum();
                stockInfoVO.setOccupyStockNum(realStock.getUsedStockNum());
            } else {
                stockInfoVO.setOccupyStockNum(CommonConstant.ZERO);
            }

            if (unRealStock != null) {
                realSalesNum += unRealStock.getSaleStockNum();
            }
            stockInfoVO.setRealSalesStockNum(realSalesNum);

            return stockInfoVO;
        }).collect(Collectors.toList());
    }


}
